std::cell

您所在的位置:网站首页 rust unsafecell std::cell

std::cell

#std::cell| 来源: 网络整理| 查看: 265

Shareable mutable containers.

Rust memory safety is based on this rule: Given an object T, it is only possible to have one of the following:

Having several immutable references (&T) to the object (also known as aliasing). Having one mutable reference (&mut T) to the object (also known as mutability).

This is enforced by the Rust compiler. However, there are situations where this rule is not flexible enough. Sometimes it is required to have multiple references to an object and yet mutate it.

Shareable mutable containers exist to permit mutability in a controlled manner, even in the presence of aliasing. Cell, RefCell, and OnceCell allow doing this in a single-threaded way—they do not implement Sync. (If you need to do aliasing and mutation among multiple threads, Mutex, RwLock, OnceLock or atomic types are the correct data structures to do so).

Values of the Cell, RefCell, and OnceCell types may be mutated through shared references (i.e. the common &T type), whereas most Rust types can only be mutated through unique (&mut T) references. We say these cell types provide ‘interior mutability’ (mutable via &T), in contrast with typical Rust types that exhibit ‘inherited mutability’ (mutable only via &mut T).

Cell types come in three flavors: Cell, RefCell, and OnceCell. Each provides a different way of providing safe interior mutability.

Cell

Cell implements interior mutability by moving values in and out of the cell. That is, an &mut T to the inner value can never be obtained, and the value itself cannot be directly obtained without replacing it with something else. Both of these rules ensure that there is never more than one reference pointing to the inner value. This type provides the following methods:

For types that implement Copy, the get method retrieves the current interior value by duplicating it. For types that implement Default, the take method replaces the current interior value with Default::default() and returns the replaced value. All types have: replace: replaces the current interior value and returns the replaced value. into_inner: this method consumes the Cell and returns the interior value. set: this method replaces the interior value, dropping the replaced value.

Cell is typically used for more simple types where copying or moving values isn’t too resource intensive (e.g. numbers), and should usually be preferred over other cell types when possible. For larger and non-copy types, RefCell provides some advantages.

RefCell

RefCell uses Rust’s lifetimes to implement “dynamic borrowing”, a process whereby one can claim temporary, exclusive, mutable access to the inner value. Borrows for RefCells are tracked at runtime, unlike Rust’s native reference types which are entirely tracked statically, at compile time.

An immutable reference to a RefCell’s inner value (&T) can be obtained with borrow, and a mutable borrow (&mut T) can be obtained with borrow_mut. When these functions are called, they first verify that Rust’s borrow rules will be satisfied: any number of immutable borrows are allowed or a single immutable borrow is allowed, but never both. If a borrow is attempted that would violate these rules, the thread will panic.

The corresponding Sync version of RefCell is RwLock.

OnceCell

OnceCell is somewhat of a hybrid of Cell and RefCell that works for values that typically only need to be set once. This means that a reference &T can be obtained without moving or copying the inner value (unlike Cell) but also without runtime checks (unlike RefCell). However, its value can also not be updated once set unless you have a mutable reference to the OnceCell.

OnceCell provides the following methods:

get: obtain a reference to the inner value set: set the inner value if it is unset (returns a Result) get_or_init: return the inner value, initializing it if needed get_mut: provide a mutable reference to the inner value, only available if you have a mutable reference to the cell itself.

The corresponding Sync version of OnceCell is OnceLock.

When to choose interior mutability

The more common inherited mutability, where one must have unique access to mutate a value, is one of the key language elements that enables Rust to reason strongly about pointer aliasing, statically preventing crash bugs. Because of that, inherited mutability is preferred, and interior mutability is something of a last resort. Since cell types enable mutation where it would otherwise be disallowed though, there are occasions when interior mutability might be appropriate, or even must be used, e.g.

Introducing mutability ‘inside’ of something immutable Implementation details of logically-immutable methods. Mutating implementations of Clone. Introducing mutability ‘inside’ of something immutable

Many shared smart pointer types, including Rc and Arc, provide containers that can be cloned and shared between multiple parties. Because the contained values may be multiply-aliased, they can only be borrowed with &, not &mut. Without cells it would be impossible to mutate data inside of these smart pointers at all.

It’s very common then to put a RefCell inside shared pointer types to reintroduce mutability:

use std::cell::{RefCell, RefMut}; use std::collections::HashMap; use std::rc::Rc; fn main() { let shared_map: Rc = Rc::new(RefCell::new(HashMap::new())); // Create a new block to limit the scope of the dynamic borrow { let mut map: RefMut


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3